/**
 * @author janet
 * @date 2014-11-24
 */
package net.oscorner.commons;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.oscorner.commons.annotation.Column;
import net.oscorner.commons.annotation.Table;



/**
 * @author janet
 * @date 2014-11-24 下午4:35:24
 * 
 */
public class BaseEntity implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/**
	 * 表名
	 * */
	private BaseDao db = null;
	private int pageSize;
	private int pageNumber;
	private int offset;
	private int sqlType;
	public BaseEntity(){
	}
	
	public BaseEntity(int sqlType){
		this.sqlType = sqlType;
	}
	
	
	
	public int getPageSize() {
		if(this.pageSize < 1)
			pageSize = 20;
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public int getPageNumber() {
		if(pageNumber < 1)
			pageNumber = 1;
		return pageNumber;
	}

	public void setPageNumber(int pageNumber) {
		this.pageNumber = pageNumber;
	}

	public int getOffset() {
		this.offset = getPageSize() * (getPageNumber() -1);
		return offset;
	}

	public int getSqlType() {
		return sqlType;
	}
	public void setSqlType(int sqlType) {
		this.sqlType = sqlType;
	}
	public void save(BaseDao dao){
		try {
			this.db = dao;
			switch(this.sqlType){
				case ConstantUtil.SQL_TYPE_CREATE:
					this.getCreate();
					break;
				case ConstantUtil.SQL_TYPE_UPDATE:
					this.getUpdate();
					break;
				case ConstantUtil.SQL_TYPE_DELETE:
					this.getDelete();
					
			}
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			e.printStackTrace();
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	private void getCreate() throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchMethodException, InvocationTargetException, SQLException{
		StringBuffer sql = new StringBuffer("INSERT INTO ");
		Table t = this.getClass().getAnnotation(Table.class);
		String tableName = "";
		if(t != null && t.prefix() != null && !t.prefix().trim().equals("")){
			tableName += t.prefix();
		}
		if(t != null && t.tableName() != null && !t.tableName().trim().equals(""))
			tableName += t.tableName();
		else{
			tableName += this.getClass().getName();
		}
		sql.append(tableName);
		sql.append("(");
		Field [] fs = this.getClass().getDeclaredFields();
		List<String> params = new ArrayList<String>();
		String sp = "";
		for(Field f : fs){
			Column c = f.getAnnotation(Column.class);
			if(c != null && c.key()){
				continue;
			}
			Method m = this.getClass().getDeclaredMethod(getMethodName(f.getName()), new Class[]{});
			sql.append(sp);
			sql.append(f.getName());
			Object o = m.invoke(this, new Object[]{});
			if(o == null)
				params.add("");
			else
				params.add(o.toString());
			sp = ",";
		}
		sql.append(") VALUES(");
		sp = "";
		for (Field f:fs) {
			Column col = f.getAnnotation(Column.class);
			if(col != null && col.key())
				continue;
			sql.append(sp);
			sql.append("?");
			sp = ",";	
		}
		sql.append(")");
		db.executeInsert(sql.toString(), params.toArray());
	}
	
	private void getUpdate() throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SQLException{
		StringBuffer sb = new StringBuffer("UPDATE ");
		Table t = this.getClass().getAnnotation(Table.class);
		String tableName = "";
		if(t != null && t.prefix() != null && !t.prefix().trim().equals("")){
			tableName += t.prefix();
		}
		if(t != null && t.tableName() != null && !t.tableName().trim().equals(""))
			tableName += t.tableName();
		else{
			tableName += this.getClass().getName();
		}
		sb.append(tableName);
		String sp = " SET ";
		Field [] fields = this.getClass().getDeclaredFields();
		List<String> params = new ArrayList<String>();
		String where = " WHERE ";
		String whereParams = "";
		for(Field f : fields){
			Column ca = f.getAnnotation(Column.class);
			String columnName = f.getName();
			Method m = this.getClass().getDeclaredMethod(this.getMethodName(f.getName()), new Class[]{});
			Object o = m.invoke(this, new Object[]{});
			if(ca != null){
				if(!ca.columnName().equals("")){
					columnName = ca.columnName();
				}
				if(ca.key()){
					where += columnName + " = ? ";
					whereParams = o==null?"":o.toString();
					continue;
				}
			}
			sb.append(sp);
			sb.append(columnName);
			sb.append(" = ? ");
			params.add(o==null?"":o.toString());
			sp = ",";
		}
		sb.append(where);
		params.add(whereParams);
		db.executeUpdate(sb.toString(), params.toArray());
	}
	
	private void getDelete() throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SQLException{
		StringBuffer sb = new StringBuffer("DELETE FROM ");
		Table t = this.getClass().getAnnotation(Table.class);
		String tableName = "";
		if(t != null && t.prefix() != null && !t.prefix().trim().equals("")){
			tableName += t.prefix();
		}
		if(t != null && t.tableName() != null && !t.tableName().trim().equals(""))
			tableName += t.tableName();
		else{
			tableName += this.getClass().getName();
		}
		sb.append(tableName);
		String sp = " WHERE ";
		List<String> params = new ArrayList<String>();
		Field[] fields = this.getClass().getDeclaredFields();
		for(Field f :fields){
			Column c = f.getAnnotation(Column.class);
			if(c != null && c.key()){
				sb.append(sp);
				if(!c.columnName().equals("")){
					sb.append(c.columnName());
				}else{
					sb.append(f.getName());
				}
				sb.append(" = ? ");
				sp = " AND ";
				Method m = this.getClass().getDeclaredMethod(this.getMethodName(f.getName()), new Class[]{});
				Object o = m.invoke(this, new Object[]{});
				params.add(o==null ? "":o.toString());
			}
		}
		db.executeDelete(sb.toString(), params.toArray());
	}
	
	@SuppressWarnings("rawtypes")
	public List find(BaseDao db) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, SQLException{
		this.db = db;
		List list = new ArrayList();
		StringBuffer sbQuery = new StringBuffer("SELECT ");
		Field [] fields = this.getClass().getDeclaredFields();
		List<String> params = new ArrayList<String>();
		String sp = "";
		StringBuffer sbWhere = new StringBuffer(" WHERE ");
		for(Field f :fields){
			Column col = f.getAnnotation(Column.class);
			String colName = f.getName();
			if(col != null && !col.columnName().trim().equals("")){
				colName = col.columnName();
			}
			sbQuery.append(sp);
			sbQuery.append(colName);
			sp = ",";
			Method m = this.getClass().getDeclaredMethod(this.getMethodName(f.getName()), new Class[]{});
			Object o = m.invoke(this, new Object[]{});
			if(o != null){
				sbWhere.append(colName);
				sbWhere.append(" =  ? ");
				params.add(o.toString());
			}
		}
		sbQuery.append(" FROM ");
		Table t = this.getClass().getAnnotation(Table.class);
		String tableName = "";
		if(t != null && t.prefix() != null && !t.prefix().trim().equals("")){
			tableName += t.prefix();
		}
		if(t != null && t.tableName() != null && !t.tableName().trim().equals(""))
			tableName += t.tableName();
		else{
			tableName += this.getClass().getName();
		}
		sbQuery.append(tableName);
		if(!sbWhere.toString().equals(" WHERE "))
			sbQuery.append(sbWhere);
		list = db.executeQuery(sbQuery.toString(), params.toArray(), this.getClass());
		return list;
	}
	private String getMethodName(String field){
		String tmp = field.substring(0,1).toUpperCase() + field.substring(1);
		return "get"+tmp;
	}
	
	
	public Map<String, String> getViewNames(){
		Map<String, String> fileds = new HashMap<String, String>();
		Field [] fs = this.getClass().getDeclaredFields();
		for (Field f : fs) {
			Column c = f.getAnnotation(Column.class);
			String viewName = c == null || c.viewName()==null|| c.viewName().equals("")?f.getName():c.viewName();
			String filedName = f.getName();
			if(c != null && c.isShow()){
				fileds.put(filedName, viewName);
			}
		}
		return fileds;
	}
	
}
